package com.netease.nim.demo.main.fragment;

import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;

import com.NewActionHelp;
import com.google.gson.reflect.TypeToken;
import com.netease.nim.demo.NimCache;
import com.netease.nim.demo.common.adapter.TAdapter;
import com.netease.nim.demo.common.adapter.TAdapterDelegate;
import com.netease.nim.demo.common.adapter.TViewHolder;
import com.netease.nim.demo.common.ui.dialog.CustomAlertDialog;
import com.netease.nim.demo.common.ui.dialog.CustomAlertDialog.onSeparateItemClickListener;
import com.netease.nim.demo.common.ui.listview.ListViewUtil;
import com.netease.nim.demo.contact.cache.ContactDataCache;
import com.netease.nim.demo.contact.cache.TeamDataCache;
import com.netease.nim.demo.contact.cache.TeamMemberInfoCache;
import com.netease.nim.demo.contact.model.Buddy;
import com.netease.nim.demo.contact.protocol.ContactHttpClient;
import com.netease.nim.demo.contact.protocol.IContactHttpCallback;
import com.netease.nim.demo.main.helper.MessageHelper;
import com.netease.nim.demo.main.model.MainTab;
import com.netease.nim.demo.main.reminder.ReminderManager;
import com.netease.nim.demo.main.viewholder.CommonRecentViewHolder;
import com.netease.nim.demo.main.viewholder.IMRecentViewHolder;
import com.netease.nim.demo.main.viewholder.RecentViewHolder;
import com.netease.nim.demo.main.viewholder.TeamRecentViewHolder;
import com.netease.nim.demo.session.activity.P2PMessageActivity;
import com.netease.nim.demo.session.activity.TeamMessageActivity;
import com.netease.nim.demo.util.LogUtil;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.RequestCallback;
import com.netease.nimlib.sdk.auth.AuthServiceObserver;
import com.netease.nimlib.sdk.auth.ClientType;
import com.netease.nimlib.sdk.auth.OnlineClient;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.MsgServiceObserve;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.netease.nimlib.sdk.msg.model.RecentContact;
import com.netease.nimlib.sdk.team.TeamService;
import com.netease.nimlib.sdk.team.model.DismissAttachment;
import com.netease.nimlib.sdk.team.model.Team;
import com.netease.nimlib.sdk.team.model.TeamMember;
import com.shwread.android.qysw10000182.R;
import com.shwread.http.base.ObjectHttpResponseHandler;
import com.shwread.http.util.Logger;

import org.apache.http.Header;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import logic.bean.TeamMemberX;
import logic.util.Utils;


/**
 * 最近联系人列表(会话列表)
 * <p/>
 * Created by huangjun on 2015/2/1.
 */
public class RecentContactsFragment
        extends
        MainTabFragment
        implements
        TAdapterDelegate {

    private final String TAG = "RecentContactsFragment";

    public static final long RECENT_TAG_STICKY = 1;                       // 联系人置顶tag

    // view
    private ListView listView;

    private View emptyBg;

    private View notifyBar;

    private TextView emptyHint;

    // data
    private List<RecentContact> items;

    private TAdapter adapter;

    private boolean msgLoaded = false;

    public RecentContactsFragment() {
        this.setFragmentId(MainTab.RECENT_CONTACTS.fragmentId);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        onCurrent();
    }

    @Override
    public Class<? extends TViewHolder> viewHolderAtPosition(int position) {
        SessionTypeEnum type = items.get(position).getSessionType();

        switch (type) {
            case P2P:
                return IMRecentViewHolder.class;
            case Team:
                return TeamRecentViewHolder.class;
            default:
                return CommonRecentViewHolder.class;
        }
    }

    @Override
    public int getViewTypeCount() {
        return 3;
    }

    @Override
    public boolean enabled(int position) {
        return true;
    }

    private void notifyDataSetChanged() {
        adapter.notifyDataSetChanged();
        boolean empty = items.isEmpty() && msgLoaded;
        emptyBg.setVisibility(empty ? View.VISIBLE : View.GONE);
        emptyHint.setHint("还没有会话，在通讯录中找个人聊聊吧！");
    }

    @Override
    protected void onInit() {
        findViews();
        initMessageList();
        requestMessages(true);
        registerObservers(true);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        registerObservers(false);
    }

    /**
     * 查找页面控件
     */
    private void findViews() {
        listView = (ListView) this.getView().findViewById(R.id.lvMessages);
        emptyBg = getView().findViewById(R.id.emptyBg);
        notifyBar = getView().findViewById(R.id.status_notify_bar);
        notifyBar.setVisibility(View.GONE);
        emptyHint = (TextView) getView().findViewById(R.id.message_list_empty_hint);
    }

    /**
     * 初始化消息列表
     */
    private void initMessageList() {
        items = new ArrayList<RecentContact>();

        adapter = new TAdapter(getActivity(), items, this);
        listView.setAdapter(adapter);
        listView.setItemsCanFocus(true);
        listView.setOnItemClickListener(new OnItemClickListener() {

            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                RecentContact item = (RecentContact) parent.getAdapter().getItem(position);
                if (item.getAttachment() != null && item.getAttachment() instanceof DismissAttachment) {
                    Logger.e("当前群已经被解散了");
                    Utils.showToast(getActivity(), "当前群已解散");
                    removeTeamInfo(item);
                    return;
                }
                talkto(item);
            }
        });
        listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {

            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (position < listView.getHeaderViewsCount()) {
                    return false;
                }
                showLongClickMenu((RecentContact) parent.getAdapter().getItem(position));

                return true;
            }
        });
        listView.setOnScrollListener(new OnScrollListener() {

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                adapter.onMutable(scrollState == SCROLL_STATE_FLING);
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

            }
        });
    }

    protected void talkto(RecentContact item) {
        if (item == null) {
            return;
        }

        switch (item.getSessionType()) {
            case P2P:
                P2PMessageActivity.start(getActivity(), item.getContactId());
                break;
            case Team:
                TeamMessageActivity.start(getActivity(), item.getContactId());
                break;
            default:
                break;
        }
    }

    private void showLongClickMenu(final RecentContact recent) {
        CustomAlertDialog alertDialog = new CustomAlertDialog(getActivity());
        alertDialog.setTitle(MessageHelper.getName(recent.getContactId(), recent.getSessionType()));
        String title = getString(R.string.main_msg_list_delete_chatting);
        alertDialog.addItem(title, new onSeparateItemClickListener() {
            @Override
            public void onClick() {
                // 删除会话，删除后，消息历史被一起删除
                NIMClient.getService(MsgService.class).deleteRecentContact(recent);
                NIMClient.getService(MsgService.class).clearChattingHistory(recent.getContactId(), recent.getSessionType());
                items.remove(recent);
                ReminderManager.getInstance().updateSessionDeltaUnreadNum(-1 * recent.getUnreadCount());
                notifyDataSetChanged();
            }
        });

        title = ((recent.getTag() & RECENT_TAG_STICKY) == 0 ? getString(R.string.main_msg_list_sticky_on_top) : getString(R.string.main_msg_list_clear_sticky_on_top));
        alertDialog.addItem(title, new onSeparateItemClickListener() {
            @Override
            public void onClick() {
                if ((recent.getTag() & RECENT_TAG_STICKY) == 0) {
                    addTag(recent, RECENT_TAG_STICKY);
                } else {
                    removeTag(recent, RECENT_TAG_STICKY);
                }
                NIMClient.getService(MsgService.class).updateRecent(recent);

                refreshMessages(false);
            }
        });
        alertDialog.show();
    }

    private void addTag(RecentContact recent, long tag) {
        tag = recent.getTag() | tag;
        recent.setTag(tag);
    }

    private void removeTag(RecentContact recent, long tag) {
        tag = recent.getTag() & ~tag;
        recent.setTag(tag);
    }

//	private List<RecentContact> loadedRecents;

    private void requestMessages(boolean delay) {
        if (msgLoaded) {
            return;
        }
        getHandler().postDelayed(new Runnable() {

            @Override
            public void run() {
                if (msgLoaded) {
                    return;
                }

                NIMClient.getService(MsgService.class).queryRecentContacts().setCallback(new RequestCallback<List<RecentContact>>() {

                    @Override
                    public void onSuccess(List<RecentContact> recents) {
//						loadedRecents = recents;

                        // 需要请求群信息的群ID
                        ArrayList<String> tids = new ArrayList<String>();
                        ArrayList<String> pids = new ArrayList<String>();
                        for (RecentContact r : recents) {
                            if (r.getAttachment() != null && r.getAttachment() instanceof DismissAttachment) {
                                Logger.e("当前群已经被解散了");
                                removeTeamInfo(r);
                            } else {
                                items.add(r);
                            }
                            if (r.getSessionType() == SessionTypeEnum.Team && !TeamDataCache.getInstance().isTeamInCache(r.getContactId())) {
                                tids.add(r.getContactId());
                                if (TeamMemberInfoCache.getInstance().getTeamMember(r.getContactId()) == null) {
                                    qryTeamMember(r.getContactId());
                                }
                            }
                            if (r.getSessionType() == SessionTypeEnum.P2P && TeamMemberInfoCache.getInstance().getTeammMemberInfo(r.getContactId()) == null) {
                                pids.add(r.getContactId());
                            }
                        }
                        qryStaffInfo(pids);

                        if (tids.isEmpty()) {
                            msgLoaded = true;
                            if (isAdded()) {
                                onRecentsLoaded();
                            }

                            return;
                        }

                        NIMClient.getService(TeamService.class).queryTeamListById(tids).setCallback(new RequestCallback<List<Team>>() {
                            @Override
                            public void onSuccess(List<Team> teams) {
                                TeamDataCache.getInstance().addOrUpdateTeam(teams);

                                msgLoaded = true;
                                if (isAdded()) {
                                    onRecentsLoaded();
                                }
                            }

                            @Override
                            public void onFailed(int code) {

                            }

                            @Override
                            public void onException(Throwable exception) {

                            }
                        });
                    }

                    @Override
                    public void onFailed(int code) {
                    }

                    @Override
                    public void onException(Throwable exception) {
                    }
                });
            }
        }, delay ? 250 : 0);
    }

    private void qryStaffInfo(ArrayList<String> pids) {
        if (null == pids || pids.isEmpty()) return;
        NewActionHelp.qryStaffInfoByAccIds(getActivity(), pids.toString(), new ObjectHttpResponseHandler<List<TeamMemberX>>() {
            @Override
            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                String errorMsg = "request team member list failed :" + statusCode;
                LogUtil.e(TAG, errorMsg);
            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, List<TeamMemberX> object, String responseString) {
                if (object != null && !object.isEmpty()) {
                    TeamMemberInfoCache.getInstance().add(object);
                    refreshMessages(false);
                }
            }

            @Override
            public Type getType() {
                return new TypeToken<List<TeamMemberX>>() {
                }.getType();
            }
        });
    }

    private void qryTeamMember(final String teamId) {
        NewActionHelp.qryMemberListByTeamId(getActivity(), teamId, new ObjectHttpResponseHandler<List<TeamMemberX>>() {
            @Override
            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, List<TeamMemberX> object, String responseString) {
                if (object != null && !object.isEmpty()) {
                    TeamMemberInfoCache.getInstance().addTeam(teamId, object);
                    TeamMemberInfoCache.getInstance().add(object);
                }
            }

            @Override
            public Type getType() {
                return new TypeToken<List<TeamMemberX>>() {
                }.getType();
            }
        });
    }

    protected void onRecentsLoaded() {
//		items.clear();
//		if (loadedRecents != null)
        if (items != null) {
//			items.addAll(loadedRecents);
            refreshMessages(true);
            requestBuddyInfo(getRequestBuddyAccounts(items));
        } else {
            refreshMessages(false);
        }
    }

    public void refreshMessages(boolean unreadChanged) {
        sortRecentContacts(items);
        notifyDataSetChanged();

        if (unreadChanged) {
            int unreadNum = 0;
            for (RecentContact r : items) {
                unreadNum += r.getUnreadCount();
            }
            ReminderManager.getInstance().updateSessionUnreadNum(unreadNum);
        }
    }

    private void requestBuddyInfo(List<String> accounts) {
        if (accounts == null || accounts.isEmpty()) {
            return;
        }

        Log.i(TAG, "MessageList request buddy info, accounts:" + accounts.toString());
        ContactHttpClient.getInstance().getUserInfo(accounts, new IContactHttpCallback<List<Buddy>>() {
            @Override
            public void onSuccess(List<Buddy> buddies) {
                ContactDataCache.getInstance().addOrUpdateBuddies(buddies);
                notifyDataSetChanged();
            }

            @Override
            public void onFailed(int code, String errorMsg) {

            }
        });
    }

    private List<String> getRequestBuddyAccounts(final List<RecentContact> recentContacts) {
        List<String> accounts = new ArrayList<String>();
        for (RecentContact r : recentContacts) {
            if (r.getFromAccount() != null && r.getSessionType() == SessionTypeEnum.P2P && !r.getFromAccount().equals(NimCache.getAccount()) && !ContactDataCache.getInstance().hasBuddy(r.getFromAccount())) {
                accounts.add(r.getFromAccount());
            }
        }

        return accounts;
    }

    /**
     * **************************** 排序 ***********************************
     */
    private void sortRecentContacts(List<RecentContact> list) {
        if (list.size() == 0) {
            return;
        }
        Collections.sort(list, comp);
    }

    private static Comparator<RecentContact> comp = new Comparator<RecentContact>() {

        @Override
        public int compare(RecentContact o1, RecentContact o2) {
            // 先比较置顶tag
            long sticky = (o1.getTag() & RECENT_TAG_STICKY) - (o2.getTag() & RECENT_TAG_STICKY);
            if (sticky != 0) {
                return sticky > 0 ? -1 : 1;
            } else {
                long time = o1.getTime() - o2.getTime();
                return time == 0 ? 0 : (time > 0 ? -1 : 1);
            }
        }
    };

    /**
     * ********************** 收消息，处理状态变化 ************************
     */
    private void registerObservers(boolean register) {
        MsgServiceObserve service = NIMClient.getService(MsgServiceObserve.class);
        service.observeRecentContact(messageObserver, register);
        service.observeMsgStatus(statusObserver, register);
        service.observeRecentContactDeleted(deleteObserver, register);
        NIMClient.getService(AuthServiceObserver.class).observeOtherClients(clientsObserver, register);
        registerTeamUpdateObserver(register);
        registerTeamMemberUpdateObserver(register);
        registerBuddyUpdateObserver(register);
    }

    /**
     * 注册群信息&群成员更新监听
     */
    private void registerTeamUpdateObserver(boolean register) {
        if (register) {
            TeamDataCache.getInstance().registerTeamDataChangedObserver(teamDataChangedObserver);
        } else {
            TeamDataCache.getInstance().unregisterTeamDataChangedObserver(teamDataChangedObserver);
        }
    }

    private void registerTeamMemberUpdateObserver(boolean register) {
        if (register) {
            TeamDataCache.getInstance().registerTeamMemberDataChangedObserver(teamMemberDataChangedObserver);
        } else {
            TeamDataCache.getInstance().unregisterTeamMemberDataChangedObserver(teamMemberDataChangedObserver);
        }
    }

    /**
     * 注册好友信息更新监听
     */
    private void registerBuddyUpdateObserver(boolean register) {
        if (register) {
            ContactDataCache.getInstance().registerBuddyDataChangedObserver(buddyDataChangedObserver);
        } else {
            ContactDataCache.getInstance().unregisterBuddyDataChangedObserver(buddyDataChangedObserver);
        }
    }

    Observer<List<RecentContact>> messageObserver = new Observer<List<RecentContact>>() {
        @Override
        public void onEvent(List<RecentContact> messages) {
            int index;
            for (RecentContact msg : messages) {
                index = -1;
                for (int i = 0; i < items.size(); i++) {
                    if (msg.getContactId().equals(items.get(i).getContactId()) && msg.getSessionType() == (items.get(i).getSessionType())) {
                        index = i;
                        break;
                    }
                }

                if (index >= 0) {
                    items.remove(index);
                }

                items.add(msg);
            }

            refreshMessages(true);

            requestBuddyInfo(getRequestBuddyAccounts(messages));
        }
    };

    Observer<IMMessage> statusObserver = new Observer<IMMessage>() {
        @Override
        public void onEvent(IMMessage message) {
            int index = getItemIndex(message.getUuid());
            if (index >= 0 && index < items.size()) {
                RecentContact item = items.get(index);
                item.setMsgStatus(message.getStatus());
                refreshViewHolderByIndex(index);
            }
        }
    };

    Observer<RecentContact> deleteObserver = new Observer<RecentContact>() {
        @Override
        public void onEvent(RecentContact recentContact) {
            if (recentContact != null) {
                for (RecentContact item : items) {
                    if (TextUtils.equals(item.getContactId(), recentContact.getContactId()) && item.getSessionType() == recentContact.getSessionType()) {
                        items.remove(item);
                        refreshMessages(true);
                        break;
                    }
                }
            } else {
                items.clear();
                refreshMessages(true);
            }
        }
    };

    TeamDataCache.TeamDataChangedObserver teamDataChangedObserver = new TeamDataCache.TeamDataChangedObserver() {

        @Override
        public void onUpdateTeams(List<Team> teams) {
            adapter.notifyDataSetChanged();
        }

        @Override
        public void onRemoveTeam(Team team) {
            //TODO 解散群
            for (RecentContact item : items) {
                if (TextUtils.equals(item.getContactId(), team.getId())) {
                    removeTeamInfo(item);
                    items.remove(item);
                    refreshMessages(true);
                    break;
                }
            }
        }
    };

    private void removeTeamInfo(RecentContact item) {
        NIMClient.getService(MsgService.class).deleteRecentContact2(item.getContactId(), item.getSessionType());
        NIMClient.getService(MsgService.class).clearChattingHistory(item.getContactId(), item.getSessionType());

    }

    TeamDataCache.TeamMemberDataChangedObserver teamMemberDataChangedObserver = new TeamDataCache.TeamMemberDataChangedObserver() {
        @Override
        public void onUpdateTeamMember(List<TeamMember> members) {
            adapter.notifyDataSetChanged();
        }

        @Override
        public void onRemoveTeamMember(TeamMember member) {

        }
    };

    ContactDataCache.BuddyDataChangedObserver buddyDataChangedObserver = new ContactDataCache.BuddyDataChangedObserver() {
        @Override
        public void onUpdateBuddies(List<Buddy> buddies) {
            adapter.notifyDataSetChanged();
        }
    };

    Observer<List<OnlineClient>> clientsObserver = new Observer<List<OnlineClient>>() {
        @Override
        public void onEvent(List<OnlineClient> onlineClients) {
            if (onlineClients == null || onlineClients.size() == 0) {
                notifyBar.setVisibility(View.GONE);
            } else {
                notifyBar.setVisibility(View.VISIBLE);
                TextView status = (TextView) notifyBar.findViewById(R.id.status_desc_label);
                OnlineClient client = onlineClients.get(0);
                switch (client.getClientType()) {
                    case ClientType.Windows:
                        status.setText("Windows端在线");
                        break;
                    case ClientType.Web:
                        status.setText("Web版在线");
                        break;
                    default:
                        notifyBar.setVisibility(View.GONE);
                        break;
                }
            }
        }
    };

    private int getItemIndex(String uuid) {
        for (int i = 0; i < items.size(); i++) {
            RecentContact item = items.get(i);
            if (TextUtils.equals(item.getRecentMessageId(), uuid)) {
                return i;
            }
        }

        return -1;
    }

    protected void refreshViewHolderByIndex(final int index) {
        getActivity().runOnUiThread(new Runnable() {

            @Override
            public void run() {
                if (index < 0) {
                    return;
                }

                Object tag = ListViewUtil.getViewHolderByIndex(listView, index);
                if (tag instanceof RecentViewHolder) {
                    RecentViewHolder viewHolder = (RecentViewHolder) tag;
                    viewHolder.refreshCurrentItem();
                }
            }
        });
    }

    @Override
    protected void updateList() {
        requestMessages(false);
    }

}
